package org.neogenesis.web.dao;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import javax.transaction.Transaction;

import org.neogenesis.web.Configurations;
import org.neogenesis.web.Utils;
import org.neogenesis.web.model.Experiment;
import org.neogenesis.web.model.Organism;
import org.neogenesis.web.model.Platform;
import org.neogenesis.web.model.Sample;
import org.neogenesis.web.model.SampleType;
import org.neogenesis.web.qualifier.DataRepository;

@SessionScoped
public class SampleDAO implements Serializable {

	@Inject
	@DataRepository
	private EntityManager em;

	@Inject
	private PlatformDAO platformDAO;

	String uploadedFilePath;

	public SampleDAO() {
		// TODO Auto-generated constructor stub
	}

	public void create(Sample sample) throws IOException {

		em.persist(sample);

	}

	public void edit(Sample sample) {
		em.merge(sample);
	}

	public void remove(Sample probe) {
		em.remove(em.merge(probe));
	}

	public Sample find(Object id) {
		return em.find(Sample.class, id);
	}

	public StringBuffer getSampleFileContentBuffer(Sample sample)
			throws IOException {

		StringBuffer buf = new StringBuffer();
		BufferedReader in = new BufferedReader(new FileReader(
				sample.getObservationFile()));
		String line = null;
		while ((line = in.readLine()) != null) {
			buf.append(line);
		}
		in.close();
		return buf;
	}

	public List<String[]> getSampleFileContentList(Sample sample)
			throws IOException {

		List<String[]> list = new ArrayList<String[]>();

		BufferedReader in = new BufferedReader(new FileReader(
				sample.getObservationFile()));
		String line = null;
		while ((line = in.readLine()) != null) {
			list.add(line.split(Configurations.FIELD_SEPARATOR));
		}
		in.close();
		return list;
	}

	public List<Sample> findAll() {
		CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
		cq.select(cq.from(Sample.class));
		return em.createQuery(cq).getResultList();
	}

	public List<Sample> findRange(int[] range) {
		CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
		cq.select(cq.from(Sample.class));
		javax.persistence.Query q = em.createQuery(cq);
		q.setMaxResults(range[1] - range[0]);
		q.setFirstResult(range[0]);
		return q.getResultList();
	}

	public int count() {
		javax.persistence.criteria.CriteriaQuery cq = em.getCriteriaBuilder()
				.createQuery();
		javax.persistence.criteria.Root<Sample> rt = cq.from(Sample.class);
		cq.select(em.getCriteriaBuilder().count(rt));
		javax.persistence.Query q = em.createQuery(cq);
		return ((Long) q.getSingleResult()).intValue();
	}

	public SampleType findByName(String name) {
		Query query = em.createQuery(
				"SELECT st FROM SampleType st WHERE o.name = :name",
				SampleType.class);
		query.setParameter("name", name);

		List<SampleType> sampleType = query.getResultList();

		if (sampleType.size() > 0)
			return sampleType.get(0);

		return null;
	}

	public void removeSample(Sample sample) {
		em.getTransaction().begin();
		em.remove(em.merge(sample));
		em.getTransaction().commit();
	}

	public boolean findByNameSampleExp(String nameSample, String nameExp) {

		Query q = em
				.createNativeQuery("select s.name, e.seriesiId from Sample s, "
						+ "Experiment e where s.name=:nameSample AND e.seriesiId=:nameExp");
		q.setParameter("nameSample", nameSample);
		q.setParameter("nameExp", nameExp);

		try {
			q.getSingleResult();
		} catch (NoResultException e) {
			return false;
		}

		em.close();
		return true;
	}

	public Map<String, Double> getMapProbeIdGeneExpression(Sample sample)
			throws IOException {
		String observationFile = sample.getObservationFile();
		Map<String, Double> map = new HashMap<String, Double>();
		System.out.println(observationFile);
		BufferedReader in = new BufferedReader(new FileReader(observationFile));

		String line = null;

		while ((line = in.readLine()) != null) {
			String split[] = line.split(Configurations.FIELD_SEPARATOR);
			String probeId = split[0];
			Double valueExpres = Double.parseDouble(split[1]);
			map.put(probeId, valueExpres);
		}

		in.close();

		return map;
	}

	public Sample createSampleFile(Sample sample, String fileTempPath)
			throws IOException {

		// recupero il percorso per arrivare al file del Sample che si trova
		// nella cartella "DATA"
		String webAppPath = FacesContext.getCurrentInstance()
				.getExternalContext().getRealPath("/");

		// recupero la piattaforma tramite l'id settanto nel sample per poter
		// accedere al file della piattaforma
		Platform platform = platformDAO.find(sample.getPlatformId());
		// creo un map in riferimento alle coppia(probeId,ExpressionValue)
		// presenti nel file del sample
		Map<String, Double> mapSampl = getMapProbeIdGeneExpression(sample);
		// creo un map in riferimento alle coppia(probeId,GeneId) presenti nel
		// file della piattaforma recuperata
		Map<String, Integer> mapPlat = platformDAO
				.getMapProbeIdGeneId(platform);

		// percorso di dove andrà a finire il file del sample definitivo
		String samplePath = webAppPath + Configurations.samplesPath
				+ Utils.getUniqueNameSample(sample);
		// apro lo stream del file
		BufferedWriter out = new BufferedWriter(new FileWriter(samplePath));

		// effettuo il merge dei due map
		for (String probeid : mapSampl.keySet()) {
			Integer geneId = mapPlat.get(probeid);
			
			if (geneId == null)
				continue;

			double expressionValue = mapSampl.get(probeid);
			// sovrascivo il file del sample con i valori dei due map
			out.write(geneId + "\t" + expressionValue + "\n");
		}
		out.flush();
		out.close();
		// setto il file definitivo nel campo "observationFile" del sample
		sample.setObservationFile(samplePath);

		return sample;
	}
}
